<?php
/*
 * PHP QR Code encoder Input splitting classes Based on libqrencode C library
 * distributed under LGPL 2.1 Copyright (C) 2006, 2007, 2008, 2009 Kentaro
 * Fukuchi <fukuchi@megaui.net> PHP QR Code is distributed under LGPL 3
 * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm> The following
 * data / specifications are taken from "Two dimensional symbol -- QR-code --
 * Basic Specification" (JIS X0510:2004) or "Automatic identification and data
 * capture techniques -- QR Code 2005 bar code symbology specification" (ISO/IEC
 * 18004:2006) This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of the License,
 * or any later version. This library is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details. You should have received a copy of
 * the GNU Lesser General Public License along with this library; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */
class QRsplit {
	public $dataStr = '';
	public $input;
	public $modeHint;
	
	// ----------------------------------------------------------------------
	public function __construct($dataStr, $input, $modeHint) {
		$this->dataStr = $dataStr;
		$this->input = $input;
		$this->modeHint = $modeHint;
	}
	
	// ----------------------------------------------------------------------
	public static function isdigitat($str, $pos) {
		if ($pos >= strlen ( $str ))
			return false;
		
		return ((ord ( $str [$pos] ) >= ord ( '0' )) && (ord ( $str [$pos] ) <= ord ( '9' )));
	}
	
	// ----------------------------------------------------------------------
	public static function isalnumat($str, $pos) {
		if ($pos >= strlen ( $str ))
			return false;
		
		return (QRinput::lookAnTable ( ord ( $str [$pos] ) ) >= 0);
	}
	
	// ----------------------------------------------------------------------
	public function identifyMode($pos) {
		if ($pos >= strlen ( $this->dataStr ))
			return QR_MODE_NUL;
		
		$c = $this->dataStr [$pos];
		
		if (self::isdigitat ( $this->dataStr, $pos )) {
			return QR_MODE_NUM;
		} else if (self::isalnumat ( $this->dataStr, $pos )) {
			return QR_MODE_AN;
		} else if ($this->modeHint == QR_MODE_KANJI) {
			
			if ($pos + 1 < strlen ( $this->dataStr )) {
				$d = $this->dataStr [$pos + 1];
				$word = (ord ( $c ) << 8) | ord ( $d );
				if (($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {
					return QR_MODE_KANJI;
				}
			}
		}
		
		return QR_MODE_8;
	}
	
	// ----------------------------------------------------------------------
	public function eatNum() {
		$ln = QRspec::lengthIndicator ( QR_MODE_NUM, $this->input->getVersion () );
		
		$p = 0;
		while ( self::isdigitat ( $this->dataStr, $p ) ) {
			$p ++;
		}
		
		$run = $p;
		$mode = $this->identifyMode ( $p );
		
		if ($mode == QR_MODE_8) {
			$dif = QRinput::estimateBitsModeNum ( $run ) + 4 + $ln + QRinput::estimateBitsMode8 ( 1 ) - 			// + 4 + l8
			QRinput::estimateBitsMode8 ( $run + 1 ); // - 4 - l8
			if ($dif > 0) {
				return $this->eat8 ();
			}
		}
		if ($mode == QR_MODE_AN) {
			$dif = QRinput::estimateBitsModeNum ( $run ) + 4 + $ln + QRinput::estimateBitsModeAn ( 1 ) - 			// + 4 + la
			QRinput::estimateBitsModeAn ( $run + 1 ); // - 4 - la
			if ($dif > 0) {
				return $this->eatAn ();
			}
		}
		
		$ret = $this->input->append ( QR_MODE_NUM, $run, str_split ( $this->dataStr ) );
		if ($ret < 0)
			return - 1;
		
		return $run;
	}
	
	// ----------------------------------------------------------------------
	public function eatAn() {
		$la = QRspec::lengthIndicator ( QR_MODE_AN, $this->input->getVersion () );
		$ln = QRspec::lengthIndicator ( QR_MODE_NUM, $this->input->getVersion () );
		
		$p = 0;
		
		while ( self::isalnumat ( $this->dataStr, $p ) ) {
			if (self::isdigitat ( $this->dataStr, $p )) {
				$q = $p;
				while ( self::isdigitat ( $this->dataStr, $q ) ) {
					$q ++;
				}
				
				$dif = QRinput::estimateBitsModeAn ( $p ) + 				// + 4 + la
				QRinput::estimateBitsModeNum ( $q - $p ) + 4 + $ln - QRinput::estimateBitsModeAn ( $q ); // - 4 - la
				
				if ($dif < 0) {
					break;
				} else {
					$p = $q;
				}
			} else {
				$p ++;
			}
		}
		
		$run = $p;
		
		if (! self::isalnumat ( $this->dataStr, $p )) {
			$dif = QRinput::estimateBitsModeAn ( $run ) + 4 + $la + QRinput::estimateBitsMode8 ( 1 ) - 			// + 4 + l8
			QRinput::estimateBitsMode8 ( $run + 1 ); // - 4 - l8
			if ($dif > 0) {
				return $this->eat8 ();
			}
		}
		
		$ret = $this->input->append ( QR_MODE_AN, $run, str_split ( $this->dataStr ) );
		if ($ret < 0)
			return - 1;
		
		return $run;
	}
	
	// ----------------------------------------------------------------------
	public function eatKanji() {
		$p = 0;
		
		while ( $this->identifyMode ( $p ) == QR_MODE_KANJI ) {
			$p += 2;
		}
		
		$ret = $this->input->append ( QR_MODE_KANJI, $p, str_split ( $this->dataStr ) );
		if ($ret < 0)
			return - 1;
		
		return $run;
	}
	
	// ----------------------------------------------------------------------
	public function eat8() {
		$la = QRspec::lengthIndicator ( QR_MODE_AN, $this->input->getVersion () );
		$ln = QRspec::lengthIndicator ( QR_MODE_NUM, $this->input->getVersion () );
		
		$p = 1;
		$dataStrLen = strlen ( $this->dataStr );
		
		while ( $p < $dataStrLen ) {
			
			$mode = $this->identifyMode ( $p );
			if ($mode == QR_MODE_KANJI) {
				break;
			}
			if ($mode == QR_MODE_NUM) {
				$q = $p;
				while ( self::isdigitat ( $this->dataStr, $q ) ) {
					$q ++;
				}
				$dif = QRinput::estimateBitsMode8 ( $p ) + 				// + 4 + l8
				QRinput::estimateBitsModeNum ( $q - $p ) + 4 + $ln - QRinput::estimateBitsMode8 ( $q ); // - 4 - l8
				if ($dif < 0) {
					break;
				} else {
					$p = $q;
				}
			} else if ($mode == QR_MODE_AN) {
				$q = $p;
				while ( self::isalnumat ( $this->dataStr, $q ) ) {
					$q ++;
				}
				$dif = QRinput::estimateBitsMode8 ( $p ) + 				// + 4 + l8
				QRinput::estimateBitsModeAn ( $q - $p ) + 4 + $la - QRinput::estimateBitsMode8 ( $q ); // - 4 - l8
				if ($dif < 0) {
					break;
				} else {
					$p = $q;
				}
			} else {
				$p ++;
			}
		}
		
		$run = $p;
		$ret = $this->input->append ( QR_MODE_8, $run, str_split ( $this->dataStr ) );
		
		if ($ret < 0)
			return - 1;
		
		return $run;
	}
	
	// ----------------------------------------------------------------------
	public function splitString() {
		while ( strlen ( $this->dataStr ) > 0 ) {
			if ($this->dataStr == '')
				return 0;
			
			$mode = $this->identifyMode ( 0 );
			
			switch ($mode) {
				case QR_MODE_NUM :
					$length = $this->eatNum ();
					break;
				case QR_MODE_AN :
					$length = $this->eatAn ();
					break;
				case QR_MODE_KANJI :
					if ($hint == QR_MODE_KANJI)
						$length = $this->eatKanji ();
					else
						$length = $this->eat8 ();
					break;
				default :
					$length = $this->eat8 ();
					break;
			}
			
			if ($length == 0)
				return 0;
			if ($length < 0)
				return - 1;
			
			$this->dataStr = substr ( $this->dataStr, $length );
		}
	}
	
	// ----------------------------------------------------------------------
	public function toUpper() {
		$stringLen = strlen ( $this->dataStr );
		$p = 0;
		
		while ( $p < $stringLen ) {
			$mode = self::identifyMode ( substr ( $this->dataStr, $p ), $this->modeHint );
			if ($mode == QR_MODE_KANJI) {
				$p += 2;
			} else {
				if (ord ( $this->dataStr [$p] ) >= ord ( 'a' ) && ord ( $this->dataStr [$p] ) <= ord ( 'z' )) {
					$this->dataStr [$p] = chr ( ord ( $this->dataStr [$p] ) - 32 );
				}
				$p ++;
			}
		}
		
		return $this->dataStr;
	}
	
	// ----------------------------------------------------------------------
	public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true) {
		if (is_null ( $string ) || $string == '\0' || $string == '') {
			throw new Exception ( 'empty string!!!' );
		}
		
		$split = new QRsplit ( $string, $input, $modeHint );
		
		if (! $casesensitive)
			$split->toUpper ();
		
		return $split->splitString ();
	}
}